#include "vObject.h"

Texture *vStar::Tex						= NULL;
ID3D11InputLayout *vStar::IL_BBVertex	= NULL;
ID3D11VertexShader *vStar::VS			= NULL;
ID3D11PixelShader *vStar::PS			= NULL;
ID3D11Buffer *vStar::VB					= NULL;

vStar::vStar( OBJHANDLE _obj, Scene * scene ) : vObject( _obj, scene ) {
	size = oapiGetSize( _obj );
	maxdist = 0.5*SC->GetFarPlane();
}

vStar::~vStar() {
}

void vStar::GlobalInit(TextureMgr * TM) {
	Tex = TM->LoadTextureFromFile( "star.dds", 0 );

	HRESULT hr;
	ID3DBlob *SBlob = NULL, *EBlob = NULL;

	D3D11_INPUT_ELEMENT_DESC ldesc[ ] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};

	CompileFromFile( "Modules\\D3D11Shaders\\SimpleBillBoard.fx", NULL, NULL, "VS_BillBoard", vs_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreateInputLayout( ldesc, 2, SBlob->GetBufferPointer(), SBlob->GetBufferSize(), &IL_BBVertex ) );
	HR( Dev->CreateVertexShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &VS ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\SimpleBillBoard.fx", NULL, NULL, "PS_BillBoard", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS ) );
	REL( SBlob );
	REL( EBlob );

	float BB[20] = {
		0, -1,  1,	0, 0,
		0,  1,  1,	0, 1,
		0, -1, -1,	1, 0,
		0,  1, -1,	1, 1
	};

	D3D11_BUFFER_DESC bdesc;
	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bdesc.ByteWidth = 20*4;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_IMMUTABLE;

	D3D11_SUBRESOURCE_DATA sdata;
	ZeroMemory( &sdata, sizeof(sdata) );
	sdata.pSysMem = BB;

	HR( Dev->CreateBuffer( &bdesc, &sdata, &VB ) );

	def_SunLight.ambient = D3DXCOLOR( fAmbient, fAmbient, fAmbient, 1.0f );
	def_SunLight.diffuse = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
	def_SunLight.specular = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
}

void vStar::GlobalExit(TextureMgr * TM) {
	if( Tex )	TM->ReleaseTexture( Tex );
	REL( IL_BBVertex );
	REL( VS );
	REL( PS );
	REL( VB );
}

void vStar::Update() {
	vObject::SaveData();
	vObject::Update();

	SunSize = rad;
	pSun = GPos;
}

void vStar::Render() {
//	return;

	if( !Tex )
		return;
#if _DEBUG
	wchar_t message[200];
	std::wstring vesselName = string2wstring(name);
	wsprintfW(message, L"[%s]vStar::Render()", vesselName.c_str());
	D3DPERF_BeginEvent(D3DCOLOR_ARGB(0xFF, 0, 0x40, 0x40), message);
#endif

	double dist_scale;
	float rad_scale = (float)size, size_hack; // make star look bigger at distance

	VECTOR3 bdir = unit( CPos );
	double hz = _hypot( bdir.x, bdir.z );
	double phi = atan2( bdir.z, bdir.x );

	float
		sphi = (float)sin( phi ),		cphi = (float)cos(phi),
		tx = (float)CPos.x,				ty = (float)CPos.y,			tz = (float)CPos.z;

	mWorld._11 = (float)bdir.x;			//cphi
	mWorld._12 = (float)bdir.y;			//0
	mWorld._13 = (float)bdir.z;			//sphi
	mWorld._31 = -(float)(bdir.z/hz);	//-sphi
	mWorld._32 = 0;
	mWorld._33 = (float)(bdir.x/hz);	//cphi
	mWorld._21 = -(mWorld._12*mWorld._33 - mWorld._32*mWorld._13); //0
	mWorld._22 = -(mWorld._13*mWorld._31 - mWorld._33*mWorld._11); //1
	mWorld._23 = -(mWorld._11*mWorld._32 - mWorld._31*mWorld._12); //0

	// artificially reduce size reduction with distance
	// to make star appear larger
	size_hack = (float)(1.0 + pow(CDist, 0.6)*1e-6) / 2.0f;
	rad_scale *= max(size_hack, 7.5f);
	maxdist = 0.3*SC->GetFarPlane();

	if( CDist > maxdist ) {
		dist_scale = maxdist/CDist;
		rad_scale *= (float)dist_scale;
		mWorld._41 = (float)(CPos.x * dist_scale);
		mWorld._42 = (float)(CPos.y * dist_scale);
		mWorld._43 = (float)(CPos.z * dist_scale);
	}

	// scale up sphere radius from 1 to planet radius
	mWorld._11 *= rad_scale;	mWorld._12 *= rad_scale;	mWorld._13 *= rad_scale;
	mWorld._21 *= rad_scale;	mWorld._22 *= rad_scale;	mWorld._23 *= rad_scale;
	mWorld._31 *= rad_scale;	mWorld._32 *= rad_scale;	mWorld._33 *= rad_scale;

	iCtx->RSSetState(RS_CullBack_Solid);

	D3DXMATRIX M = mWorld * *SC->GetVP();
	iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &M, 0, 0 );
	iCtx->VSSetConstantBuffers( 0, 1, &cb_D3DXMATRIX_x1 );
	static const float sunColorComponent = 50.0f;
	iCtx->UpdateSubresource( cb_D3DXVECTOR4, 0, NULL, D3DXVECTOR4( sunColorComponent, sunColorComponent, sunColorComponent, 0.5f ), 0, 0 );
	iCtx->PSSetConstantBuffers( 0, 1, &cb_D3DXVECTOR4 );

	const UINT BBVertexStride = 20, VBOffset = 0;
	iCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
	iCtx->IASetInputLayout( IL_BBVertex );
	iCtx->IASetVertexBuffers( 0, 1, &VB, &BBVertexStride, &VBOffset );
	iCtx->VSSetShader( VS, NULL, NULL );
	iCtx->PSSetShader( PS, NULL, NULL );
	iCtx->PSSetShaderResources( 0, 1, Tex->GetSRV() );
	iCtx->PSSetSamplers( 0, 1, &SS_Linear_Wrap );
	iCtx->OMSetBlendState( BS_SrcAlpha, D3DXCOLOR( 1, 1, 1, 1 ), 0xFFFFFFFF );
	iCtx->Draw( 4, 0 );
#if _DEBUG
	D3DPERF_EndEvent();
#endif
}